﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace iESELibrary.ESEHandler
{
	public class Hash : IDisposable
	{
		#region Variables
		private bool disposed = false;
		private byte[] encryptedHash;
		private byte[] value;
		#endregion

		#region Properties
		public byte[] Value
		{
			get
			{
				return this.value;
			}
		}
		#endregion

		#region Constructors
		/// <summary>
		/// Initiates SidKey(s) object with account objectSid
		/// </summary>
		/// <param name="objectSid">Account object Security-Identifier</param>
		public Hash(DESCrypto.Decryption decryptionDES, byte[] encryptedHash, RC4Crypto.Vault.PekKey pekKey, DESCrypto.Vault.SidKey sidKey)
		{
			this.encryptedHash = encryptedHash;
			System.Buffer.BlockCopy(encryptedHash, 8, this.encryptedHash, 0, encryptedHash.Length - 8);

			this.DecryptHashRC4(this.encryptedHash, pekKey);
			this.DecryptHashDES(decryptionDES, sidKey);
		}
		#endregion

		#region Enums
		#endregion

		#region Public Static Methods
		private void DecryptHashRC4(byte[] encryptedHash, RC4Crypto.Vault.PekKey pekKey)
		{
			using (MD5 hashMD5 = MD5.Create())
			{
				byte[] encHashLow = new byte[16];
				byte[] encHashHigh = new byte[16];
				Array.Copy(this.encryptedHash, 0, encHashLow, 0, 16);
				Array.Copy(this.encryptedHash, 16, encHashHigh, 0, 16);

				hashMD5.TransformBlock(pekKey.Key, 0, pekKey.Key.Length, pekKey.Key, 0);
				hashMD5.TransformFinalBlock(encHashLow, 0, 16);

				byte[] keyRC4 = hashMD5.Hash;

				RC4Crypto.Decryption.Decrypt(ref encHashHigh, keyRC4);

				this.encryptedHash = encHashHigh;
			}
		}

		private void DecryptHashHistoryDES(DESCrypto.Decryption decryptionDES, DESCrypto.Vault.SidKey sidKey)
		{
			for (int i = 0; i < this.encryptedHash.Length; i++)
			{
				int indexLow = i*16;
				int indexHigh = (i+1)*16;
				byte[] encHashPart = new byte[indexHigh - indexLow];
				System.Buffer.BlockCopy(this.encryptedHash, indexLow, encHashPart, 0, indexHigh - indexLow);
				this.value = DecryptHashDES(decryptionDES, encHashPart, sidKey);
			}
		}

		private void DecryptHashDES(DESCrypto.Decryption decryptionDES, DESCrypto.Vault.SidKey sidKey)
		{
			this.value = DecryptHashDES(decryptionDES, this.encryptedHash, sidKey);
		}

		private byte[] DecryptHashDES(DESCrypto.Decryption decryptionDES, byte[] encryptedHash, DESCrypto.Vault.SidKey sidKey)
		{
			byte[] encHashLow = new byte[8];
			byte[] encHashHigh = new byte[8];
			Array.Copy(this.encryptedHash, 0, encHashLow, 0, 8);
			Array.Copy(this.encryptedHash, 8, encHashHigh, 0, 8);

			string hashLow = BitConverter.ToString(encHashLow);
			string hashHigh = BitConverter.ToString(encHashHigh);
			string sid1 = BitConverter.ToString(sidKey.SidKey1);
			string sid2 = BitConverter.ToString(sidKey.SidKey2);
			byte[] hash = new byte[16];

			System.Buffer.BlockCopy(decryptionDES.Decrypt(encHashLow, sidKey.SidKey1), 0, hash, 0, 8);
			System.Buffer.BlockCopy(decryptionDES.Decrypt(encHashHigh, sidKey.SidKey2), 0, hash, 8, 8);

			return hash;
		}
		#endregion

		#region IDisposable Members
		public void Dispose()
		{
			Dispose(true);
			GC.SuppressFinalize(this);
		}

		protected virtual void Dispose(bool disposing)
		{
			if (!this.disposed)
			{
				if (disposing)
				{

				}

				this.disposed = true;
			}
		}
		#endregion
	}
}
